/** \file   InData.g
*   \brief  Defintion of the input data grammar 
*   \author Ameen Jaber
*   \author Mohamad Noureddine
*   \author Mohamed Sabra
*   \date   27-5-2011
*/

grammar InData;

options
{
    backtrack	= true;
    memoize   	= true;
    k	    	= 3;
    language	= C;
}

@lexer::header
{
 #define	ANTLR3_INLINE_INPUT_ASCII
}

@parser::includes
{
 #include "util.h"
 #include "defs.h"
 #include "InData.h"
 #include "TPType.h"
 #include <iostream>
 #include <string>
 #include <map>
}

@members 
{
 varTable_t * _vTable; //!<Hash table between variable and object class containing data
}

/////////// PARSER RULES //////////////
translation_unit returns [varTable_t *varMap]
@init {
            _vTable = new varTable_t();
            int count = 0;
      }
@after {
            $varMap=_vTable;
       }
    : (a = statementList {
            count++;
        })+
    ;

statementList
    : i=IDENTIFIER '=' ( a= integer {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            (*_vTable)[index] = new object($a.val);
        }
        | b= cset {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            (*_vTable)[index] = $b.ret;
        }
        | c= sequence {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            (*_vTable)[index] = $c.ret;
        }
        | d= relation {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            (*_vTable)[index] = $d.ret;
        }
        | e= function {
            char * s = new char[$i.text->len];
            sprintf(s,"\%s",$i.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            (*_vTable)[index] = $e.ret;

        } ) ';'
    ;

integer returns [int val]
    : e=CONSTANT {
            char * t = new char [$e.text->len];
            sprintf(t,"\%s",$e.text->chars); 
            int value = atoi(t);
            delete [] t;
            $val = value;
        }
    ;

cset returns [object * ret]
@init{
    pppset * myset = new pppset();
    myset->type = Set; // set type as set
}
@after {
    $ret = myset;
}   
    : '{' c=custom {
            myset->data->push_back($c.ret);
        }
        (',' d=custom {
                myset->data->push_back($d.ret);
            }
        )* '}'
    ;

sequence returns [object * ret]
@init{
    pppsequence * mysequence = new pppsequence();
    mysequence->type = Sequence;
}
@after {
    $ret = mysequence;
} 
    : '<' c=custom {
            mysequence->data->push_back($c.ret);
        }
        (','d=custom {
                mysequence->data->push_back($d.ret);
            }
        )* '>'
    ;

custom returns [object * ret]
    : i = integer {
            object * myobj = new object($i.val);
            myobj->type = Integer;
            $ret = myobj;
        } 
    | s = cset {
            $ret = $s.ret;
        }
    | q = sequence {
            $ret = $q.ret;
        }
    | r = relation {
            $ret = $r.ret;
        }
    | f = function {
            $ret = $f.ret;
        }
    | d = IDENTIFIER {
            char * s = new char[$d.text->len];
            sprintf(s,"\%s",$d.text->chars); 
            std::string index(s); // get the variable name
            delete [] s;
            varTable_t::iterator it;
            it=_vTable->find(index);
            if(it != _vTable->end()) {
                $ret = it->second;
            }
            else {
                std::cerr<<index<<" is not defined\n"<<std::endl;
                exit(-1);
            }
        }
    ;

relation returns [object * ret]
@init{
    ppprelation * myrelation = new ppprelation();
    myrelation->type = Relation;
}
@after {
    $ret = myrelation;
} 
    : '[' '(' ( a = custom ',' b = custom ) {
            Pair_t * _pair=new Pair_t($a.ret , $b.ret);
            myrelation->data->push_back(_pair);
        }
        ')' (',''(' ( c = custom ',' d = custom ) {
                Pair_t * pair2= new Pair_t($c.ret , $d.ret);
                myrelation->data->push_back(pair2);
            }
            ')')*']'
    ;

function returns [object * ret]
@init{
    pppfunction * myfunction = new pppfunction();
    myfunction->type = Function;
}
@after {
    $ret = myfunction;
} 
    : '@[' '(' (a = custom ',' b = custom ) {
            Pair_t * _pair=new Pair_t($a.ret , $b.ret);
            myfunction->data->push_back(_pair);
        }
        ')' (',''(' (c = custom ',' d = custom ) {
                Pair_t * pair2=new Pair_t($c.ret , $d.ret);
                myfunction->data->push_back(pair2);
            }
            ')')*']@'
    ;


/////////////////// LEXER RULES //////////////////////
CONSTANT 
    : DECIMAL_LITERAL
    ;

// Basics 
IDENTIFIER
    : LETTER (LETTER | '0'..'9')*
    ;

fragment 
LETTER
    : '$'
    | 'A'..'Z'
    | 'a'..'z'
    | '_'
    ;

fragment
DECIMAL_LITERAL 
    : ('0' | '1'..'9' '0'..'9'*);

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
    ;
